﻿//Author:Michal Sporna
//License: https://operationsneakpeek.codeplex.com/license

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.GamerServices;


namespace World.Classes
{
    /// <summary>
    /// represents a secret word that player has to lay from collected words
    /// or guess
    /// </summary>
    public class SecretWord
    {
        #region properties
        public string Word;
        public Color ColorInInventory;
        public List<Letter> Letters;
        public bool Solved;
       


        #endregion

        #region METHODS

        /// <summary>
        /// default constructor
        /// </summary>
        public SecretWord()
        {
            Word = null;
            Letters = null;
            Solved = false;
            ColorInInventory = Color.Red;
        }

        /// <summary>
        /// Init word-prepare it when map is started for the first time ever
        /// </summary>
        public void Init()
        {
            //declare
            Random random;
            int randomIndex = -1;
            //Letter newLetter = null;
            //SpriteFont letterFontFace;


            try
            {
                //if word propositions are not null, then process them, get 1 random word from the list
                if (Levels.LevelManager.CurrentMap.WordPropositions != null)
                {
                    random = new Random();

                    randomIndex = random.Next(0,Levels.LevelManager.CurrentMap.WordPropositions.Count);

                    random = null;

                    //if random index is 0 or more, then probably some random index has been drawn. 
                    if (randomIndex >= 0 && randomIndex < Levels.LevelManager.CurrentMap.WordPropositions.Count)
                    {
                        this.Word = Levels.LevelManager.CurrentMap.WordPropositions[randomIndex].String;
                    }
                    else
                    {
                        //get first word by default, if something goes wrong
                        this.Word = Levels.LevelManager.CurrentMap.WordPropositions[0].String;
                    }

                    //if word is not null
                    if (this.Word != null)
                    {
                        //init list of letters-it is supposed to be claled only once, as this method is called only once (first time the game is loaded,after that everything is loaded from storage)
                        this.Letters = new List<Letter>();

                        //THIS NOW IS SET IN GAME.UPDATE AFTER NODES ARE CREATED
                        //set letters (assign letters to map cells)
                        //this.SetLetters();

                       

                       

                        //save initial data
                        StorageManager.SaveWordInitialData();
                    }

                    //clear
                    //newLetter = null;
                    Levels.LevelManager.CurrentMap.WordPropositions = null;

                }



            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// Set letters-assign each letter
        /// to a mapCell
        /// </summary>
        public void SetLetters()
        {
            //declare
            List<int> processedLetterIndexes;
            Letter newLetter = null;
            string secretWordCopy = this.Word;

            try
            {

                if (this.Letters != null)
                {
                    processedLetterIndexes = new List<int>();

                    for (int i = 0; i < Levels.LevelManager.CurrentMap.MapCells.Count; i++)
                    {
                        //foreach letter placement
                        for (int i1 = 0; i1 < Levels.LevelManager.CurrentMap.LetterPlacements.Count; i1++)
                        {

                            //if this placement is for the currently processed map cell
                            //and letter setting is for chosen word
                            if (Levels.LevelManager.CurrentMap.MapCells[i].ID.ToLower() == Levels.LevelManager.CurrentMap.LetterPlacements[i1].MapCellID.ToLower() && Levels.LevelManager.CurrentMap.LetterPlacements[i1].Word==this.Word)
                            {

                                //create new instance of letter
                                newLetter = new Letter();
                                newLetter.LetterString = Levels.LevelManager.CurrentMap.LetterPlacements[i1].Letter;
                                newLetter.Pos = new int[] { Levels.LevelManager.CurrentMap.LetterPlacements[i1].X, Levels.LevelManager.CurrentMap.LetterPlacements[i1].Y };
                                newLetter.MapCellID = Levels.LevelManager.CurrentMap.MapCells[i].ID;
                                newLetter.IndexInWord = Levels.LevelManager.CurrentMap.LetterPlacements[i1].Index;

                                //set has letter
                                if (World.WorldManager.Nodes != null)
                                {
                                    for (int n = 0; n < World.WorldManager.Nodes.Count; n++)
                                    {
                                        if (World.WorldManager.Nodes[n].ID == newLetter.Pos[0] && World.WorldManager.Nodes[n].ID == newLetter.Pos[1])
                                        {
                                            World.WorldManager.Nodes[n].HasLetter = true;
                                            break;
                                        }
                                    }
                                }


                                //add
                                this.Letters.Add(newLetter);


                            } //if placement setting found

                          

                        }//foreach letter placement
                    }//foreach map cell


                }

                //save
                StorageManager.SaveWordInitialData();


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// Position letters
        /// in the map cell
        /// </summary>
        public void PositionLetters()
        {
            //declare
            Random random;
            int randomIndex;
            bool walkableNodeFound;

            bool skipThisIndex = false;


            List<World.Node> Nodes = World.WorldManager.Nodes;//copy of the nodes
            List<int> processedLetters = new List<int>();
            List<int[]> positionedLetters = new List<int[]>();//list of positions of letters that have already assigned positions

            try
            {
            

                if (this.Letters != null && !Levels.LevelManager.CurrentMap.CurrentMapCell.LettersPlaced)
                {
                    //foreach letter
                    for (int i = 0; i < this.Letters.Count; i++)
                    {
                        //if letter is assigned to the current map cell, 
                        //and is not yet uncovered, then add
                        //to a random pos on the map
                        if (this.Letters[i].MapCellID.ToLower() == Levels.LevelManager.CurrentMap.CurrentMapCell.ID.ToLower() && !this.Letters[i].Uncovered)
                        {

 
                            walkableNodeFound = false;


                            //keep looking for a free, random node
                            while (!walkableNodeFound)
                            {
                                random = new Random();
                                randomIndex = random.Next(0, Nodes.Count);

                                if (processedLetters.Contains(randomIndex))
                                {
                                    continue;
                                }


                                skipThisIndex = false;

                                #region does node contain bomb
                                //letter cannot be on the same node as bomb
                                for (int i1 = 0; i1 < Levels.LevelManager.CurrentMap.CurrentMapCell.Bombs.Count; i1++)
                                {
                                    if (Levels.LevelManager.CurrentMap.CurrentMapCell.Bombs[i1].Position.X == Nodes[randomIndex].Rectangle.X && Levels.LevelManager.CurrentMap.CurrentMapCell.Bombs[i1].Position.Y == Nodes[randomIndex].Rectangle.Y)
                                    {
                                        skipThisIndex = true;
                                        break;
                                    }
                                }

                                #endregion
                                #region is node prohibited from putting a letter in it

                                //for (int i1 = 0; i1 < Levels.LevelManager.CurrentMap.CurrentMapCell.ProhibitedNodesForLetters.Count; i1++)
                                //{
                                //    if (Levels.LevelManager.CurrentMap.CurrentMapCell.ProhibitedNodesForLetters[i1][0] == Nodes[randomIndex].Rectangle.X && Levels.LevelManager.CurrentMap.CurrentMapCell.ProhibitedNodesForLetters[i1][1] == Nodes[randomIndex].Rectangle.Y)
                                //    { 
                                //        //.cannot use this node
                                //        skipThisIndex = true;
                                //        break;
                                    
                                //    }

                                //}

                                #endregion

                                if (skipThisIndex)
                                {
                                    //remove the node from the list as it's useless
                                    //Nodes.RemoveAt(randomIndex);
                                    processedLetters.Add(randomIndex);

                                    continue;

                                    
                                }

                                //if not walkable node or the one that already has letter was drawn
                                //then draw again
                                if (Nodes[randomIndex].IsWalkable && !Nodes[randomIndex].HasLetter)
                                {

                                    #region is there a letter in neigbouring node

                                    for (int nn = 0; nn < positionedLetters.Count; nn++)
                                    {
                                        //node on the right
                                        if (positionedLetters[nn][0] == Nodes[randomIndex].Rectangle.X + World.WorldManager.WorldConfig.NodeWidth && positionedLetters[nn][1] == Nodes[randomIndex].Rectangle.Y)
                                        {
                                            skipThisIndex = true;
                                            break;
                                        }

                                        //node on the left
                                        if (positionedLetters[nn][0] == Nodes[randomIndex].Rectangle.X - World.WorldManager.WorldConfig.NodeWidth && positionedLetters[nn][1] == Nodes[randomIndex].Rectangle.Y)
                                        {
                                            skipThisIndex = true;
                                            break;
                                        }

                                        //node above
                                        if (positionedLetters[nn][0] == Nodes[randomIndex].Rectangle.X && positionedLetters[nn][1] == Nodes[randomIndex].Rectangle.Y - World.WorldManager.WorldConfig.NodeHeight)
                                        {
                                            skipThisIndex = true;
                                            break;
                                        }

                                        //node below
                                        if (positionedLetters[nn][0] == Nodes[randomIndex].Rectangle.X && positionedLetters[nn][1] == Nodes[randomIndex].Rectangle.Y + World.WorldManager.WorldConfig.NodeHeight)
                                        {
                                            skipThisIndex = true;
                                            break;
                                        }
                                    }


                                    if (skipThisIndex)
                                    {
                                        //remove the node from the list as it's useless
                                        Nodes.RemoveAt(randomIndex);

                                        continue;


                                    }

                                    #endregion

                                    this.Letters[i].Pos = new int[] { Nodes[randomIndex].Rectangle.X, Nodes[randomIndex].Rectangle.Y };

                                    for (int n = 0; n < World.WorldManager.Nodes.Count; n++)
                                    {
                                        if (World.WorldManager.Nodes[n].ID == Nodes[randomIndex].ID && World.WorldManager.Nodes[n].Row == Nodes[randomIndex].Row)
                                        {
                                            World.WorldManager.Nodes[n].HasLetter = true;
                                            Nodes[randomIndex].HasLetter = true;
                                            break;
                                        }
                                    }
                                    //already positioned letters
                                    positionedLetters.Add(new int[] { Nodes[randomIndex].Rectangle.X, Nodes[randomIndex].Rectangle.Y });
                                    
                                    walkableNodeFound = true;

                                    

                                    //break while loop
                                    break;
                                }
                                else
                                {
                                    //remove the node from the list as it's useless
                                    //Nodes.RemoveAt(randomIndex);
                                    processedLetters.Add(randomIndex);

                                    continue;
                                }

                            }
                        }


                    }

                    //save that letters have been placed
                    Levels.LevelManager.CurrentMap.CurrentMapCell.LettersPlaced = true;
                    StorageManager.SaveLettersPositionedFlag(Levels.LevelManager.CurrentMap.CurrentMapCell.ID);

                    //set warmth for the nodes in this map cell
                    //World.WorldManager.SetWarmthForEachNode();
                }


            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }

        /// <summary>
        /// Shows a phone keyboard
        /// and allows user to guess a secret word
        /// </summary>
        public void GuessThePassword()
        {
            try
            {
                //if player still has some pass guesses
                if (Levels.LevelManager.CurrentMap.WildPasswordGuesses <= Levels.LevelManager.CurrentMap.DefaultWildPassGuessesNumber && Levels.LevelManager.CurrentMap.WildPasswordGuesses>0)
                {
                    //if keyboard not shown already
                    if (!Guide.IsVisible)
                    {
                        //show the keyboard
                        Guide.BeginShowKeyboardInput(PlayerIndex.One, "Bomb Password Guesses Left: " + Levels.LevelManager.CurrentMap.WildPasswordGuesses.ToString(), PrepareSecretString(), string.Empty, new AsyncCallback(GotPassword), this);
                    }

                }
                else
                {
                    //inform player that no more guessing tries (need to buy this)
                    Util.MessageBox.ShowMessage("You have no more free guesses! Go to the store and buy some.");
                    return;
                }



            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        /// <summary>
        /// got password
        /// </summary>
        /// <param name="result"></param>
        public void GotPassword(IAsyncResult result)
        {
            //declare
            string password;

            try
            {
                if (result.IsCompleted)
                {
                    //close the keyboard
                    password = Guide.EndShowKeyboardInput(result);

                    //if player entered some text
                    if (password != null)
                    {
                        //if password matches the secret word
                        if (password.ToLower().Trim() == this.Word.ToLower())
                        {
                            //word is solved
                            this.Solved = true;

                        }
                        else
                        {
                            //specified by player string does not match the secret word
                            //show message box
                            Util.MessageBox.ShowMessage("Wrong Password!");

                        }

                        //decrement 1 wild pass guess attempt
                        Levels.LevelManager.CurrentMap.WildPasswordGuesses -= 1;

                        if (Levels.LevelManager.CurrentMap.WildPasswordGuesses < 0)
                        {
                            Levels.LevelManager.CurrentMap.WildPasswordGuesses = 0;
                        }

                        //save current word state
                        StorageManager.SaveWordStateForTheMap();
                        //save bomb state for the map
                        StorageManager.SaveBombStateForTheMap();

                    }
                    else
                    {
                        //if no text input, then return n
                        return;
                    }
                }



            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return;
            }
        }


        #region UTIL

        /// <summary>
        /// Prepare secret string, meaning loop trhu letters
        /// and show uncovered,hide covered
        /// </summary>
        /// <returns></returns>
        public string PrepareSecretString()
        {
            //declare
            string secretString=string.Empty;
            string letter;

            try
            {
                if (this.Letters != null)
                {
                    for (int i = 0; i < this.Letters.Count; i++)
                    {
                        //put "_" to all places for now
                        secretString += "_ ";
                    }

                    for (int i = 0; i < this.Letters.Count; i++)
                    {
                        if (this.Letters[i].Uncovered)
                        {
                            //if uncovered add letter as is
                            letter = GetLetterByIndex(this.Letters[i].IndexInWord);

                            //replace _ with letter
                            secretString = secretString.Remove(this.Letters[i].IndexInWord*2,1);
                            secretString = secretString.Insert(this.Letters[i].IndexInWord*2, letter);
                        }
                       
                    }
                }

                return secretString;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return string.Empty;
            }

        }

        /// <summary>
        /// get letter by index
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public string GetLetterByIndex(int index)
        {
            

            try
            {
                if (this.Letters != null)
                {
                    for (int i = 0; i < this.Letters.Count; i++)
                    {
                        if (this.Letters[i].IndexInWord == index)
                        {

                            return this.Letters[i].LetterString;
                        }
                    }
                }

                return string.Empty;

            }
            catch (Exception ex)
            {
                Util.ErrorLogging.LogError(ex);
                return string.Empty;
            }
        }


        #endregion


        #endregion

    }
}
